
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>
// 定义超级块结构体
struct ext4_super_block {
    uint32_t s_inodes_count;        // inode节点数
    uint32_t s_blocks_count;        // 总块数
    uint32_t s_r_blocks_count;      // 保留块数
    uint32_t s_free_blocks_count;   // 空闲块数
    uint32_t s_free_inodes_count;   // 空闲inode节点数
    uint32_t s_first_data_block;    // 第一个数据块
    uint32_t s_log_block_size;      // 数据块大小的对数值
    uint32_t s_inode_size;          // inode大小
    uint32_t s_block_group_nr;      // 块组号
    uint32_t s_feature_compat;      // 兼容特性位图
    uint32_t s_feature_incompat;    // 不兼容特性位图
    uint32_t s_feature_ro_compat;   // 只读兼容特性位图
};

// 定义组描述符结构体
struct ext4_group_desc {
    uint32_t bg_block_bitmap;      // 块位图所在块号
    uint32_t bg_inode_bitmap;      // inode位图所在块号
    uint32_t bg_inode_table;       // inode表起始块号
    uint16_t bg_free_blocks_count; // 空闲块数
    uint16_t bg_free_inodes_count; // 空闲inode数
};

// 定义位图结构体
struct ext4_bitmap {
    unsigned char *data;        // 实际的位图数据
};

// 定义inode结构体
struct ext4_inode {
    uint16_t    i_mode;     // 文件模式
    uint16_t    i_uid;      // 用户ID
    uint32_t    i_size;     // 文件大小
    uint32_t    i_atime;    // 最后访问时间
    uint32_t    i_ctime;    // 创建时间
    uint32_t    i_mtime;    // 最后修改时间
};
void print_super_block(struct ext4_super_block *sb) {
	printf("超级块信息\n");
    printf("文件系统类型标识: %u\n", sb->s_feature_compat);
    printf("文件系统大小: %u\n", sb->s_blocks_count);
    printf("数据块大小: %u\n", 1024 << sb->s_log_block_size);
    printf("inode大小: %u\n", sb->s_inode_size);
    printf("块组大小: %u\n", sb->s_blocks_count / sb->s_block_group_nr);
    printf("总块数: %u\n", sb->s_blocks_count);
    printf("inode节点数: %u\n", sb->s_inodes_count);
    printf("空闲块数: %u\n", sb->s_free_blocks_count);
}
void print_bitmap(int fd,  uint32_t block_number, int block_size) {
    off_t offset = (off_t)block_number * block_size;
    unsigned char *bitmap = (unsigned char *)malloc(block_size);    if (lseek(fd, offset, SEEK_SET) < 0 || read(fd, bitmap, block_size) < 0) {
        perror("Error reading bitmap");
        free(bitmap);
        return;
    }

    // 打印位图数据
    for (int i = 0; i < block_size; i++) {
        for (int j = 0; j < 8; j++) {
            if (bitmap[i] & (1 << j))
                printf("1");
            else
                printf("0");
        }
        printf(" ");
    }
    printf("\n");

    free(bitmap);
}
void print_group_desc(struct ext4_group_desc *gd, int fd, int block_size) {
	printf("组描述符信息\n");
    printf("块位图所在块号: %u\n", gd->bg_block_bitmap);
    printf("inode位图所在块号: %u\n", gd->bg_inode_bitmap);
    printf("inode表起始块号: %u\n", gd->bg_inode_table);
    printf("空闲块数: %u\n", gd->bg_free_blocks_count);
    printf("空闲inode数: %u\n", gd->bg_free_inodes_count);

    printf("块位图信息:\n");
    print_bitmap(fd, gd->bg_block_bitmap, block_size);

    printf("inode位图信息:\n");
    print_bitmap(fd, gd->bg_inode_bitmap, block_size);
}

void convert_timestamp(time_t timestamp, char* buffer, size_t buffer_size) {
    struct tm *timeinfo;

    timeinfo = localtime(&timestamp);
    strftime(buffer, buffer_size, "%Y-%m-%d %H:%M:%S", timeinfo);
}

void print_inode(struct ext4_inode *inode) {
	char buffer1[80];
	char buffer2[80];
	char buffer3[80];
    convert_timestamp(inode->i_atime, buffer1, sizeof(buffer1));
	convert_timestamp(inode->i_ctime, buffer2, sizeof(buffer2));
	convert_timestamp(inode->i_mtime, buffer3, sizeof(buffer3));
	printf("inode数据项信息\n");
    printf("文件模式: %u\n", inode->i_mode);
    printf("用户ID: %u\n", inode->i_uid);
    printf("文件大小: %u\n", inode->i_size);
	
    printf("最后访问时间: %s\n", buffer1);
    printf("创建时间: %s\n", buffer2);
    printf("最后修改时间: %s\n", buffer3);
}

int main(int argc, char **argv) {
    int fd;
    struct ext4_super_block superblock;
    struct ext4_group_desc group_desc;
    struct ext4_inode inode;

	if (argc != 2) {
        fprintf(stderr, "使用方法: %s <设备>\n", argv[0]);
        exit(1);
    }
	
    // 打开块设备文件
    fd = open(argv[1], O_RDONLY);
    if (fd < 0) {
        perror("无法打开块设备");
        exit(1);
    }

    // 定位到超级块的偏移量
    off_t offset = 1024;
    if (lseek(fd, offset, SEEK_SET) < 0) {
        perror("lseek 错误");
        close(fd);
        exit(1);
    }

    // 读取超级块信息
    ssize_t bytes_read = read(fd, &superblock, sizeof(superblock));
    if (bytes_read < 0) {
        perror("读取超级块错误");
        close(fd);
        exit(1);
    }

    // 打印超级块信息
    print_super_block(&superblock);

    // 读取组描述符信息
    offset += sizeof(superblock);
    if (lseek(fd, 4096, SEEK_SET) < 0) {
        perror("lseek 错误");
        close(fd);
        exit(1);
    }
    bytes_read = read(fd, &group_desc, sizeof(group_desc));
    if (bytes_read < 0) {
        perror("读取组描述符错误");
        close(fd);
        exit(1);
    }

    // 打印组描述符信息
    print_group_desc(&group_desc, fd, 1024 << superblock.s_log_block_size);

   // 读取inode表信息
    offset = group_desc.bg_inode_table * (1024 << superblock.s_log_block_size);
	
    if (lseek(fd, offset, SEEK_SET) < 0) {
        perror("lseek 错误");
        close(fd);
        exit(1);
    }
    bytes_read = read(fd, &inode, sizeof(inode));
    if (bytes_read < 0) {
        perror("读取inode表错误");
        close(fd);
        exit(1);
    }

    // 打印第一个inode的信息
    print_inode(&inode);

    // 关闭块设备文件
    close(fd);

    return 0;
}


